package com.katze.boot.plugins.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.katze.common.ResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Date;
import java.util.function.Function;

public class JwtTokenProvider {
    private static final Logger log = LoggerFactory.getLogger(JwtTokenProvider.class);

    private static final String TOKEN_SECRET="@qwe_241205..."; //密钥盐

    private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000L;

    /**
     * 生成 token
     *
     * @param obj 用户对象或者用户名
     * @return token
     */
    public static <T>Function<TokenConsumer<T, String, Long>, String> sign(T obj, Integer days) {
        long timeout = days * EXPIRE_TIME;
        Date date = new Date(System.currentTimeMillis() + timeout);
        // 创建携带有效期的jwt
        JWTCreator.Builder builder = JWT.create().withExpiresAt(date);
        // 保存用户信息
        if (obj instanceof String username) {
            builder.withClaim("username", username);
        } else if ((obj instanceof UserDetails user)) {
            builder.withClaim("username", user.getUsername());
        }
        // 生成token
        String token = builder.sign(Algorithm.HMAC256(TOKEN_SECRET));
        return (com) -> {
            com.save(obj, token, timeout);
            return token;
        };
    }

    /**
     * 验证JWT令牌是否有效
     * @param token JWT字符串
     */
    public static ResponseStatus verify(String token, Function<DecodedJWT, ResponseStatus> action) {
        try {
            JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).build();//创建token验证器
            DecodedJWT decodedJWT = jwtVerifier.verify(token);
            if (log.isDebugEnabled()) {
                log.info("认证通过:{}, 过期时间:{}", token, decodedJWT.getExpiresAt().before(new Date()));
            }
            return action.apply(decodedJWT);
        } catch (IllegalArgumentException | JWTVerificationException e) {
            //抛出错误即为认证失败
            log.warn("认证失败:{}", token, e);
            return ResponseStatus.TOKEN_INVALID;
        }
    }
}
